// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.neuronbit.businessflow.intellij.editor.swing.editor;

import com.intellij.lang.properties.PropertiesReferenceManager;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
//import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
import com.intellij.uiDesigner.core.GridConstraints;
//import com.intellij.uiDesigner.designSurface.ComponentDropLocation;
//import com.intellij.uiDesigner.designSurface.DraggedComponentList;
//import com.intellij.uiDesigner.designSurface.GuiEditor;
//import com.intellij.uiDesigner.editor.UIFormEditor;
import com.intellij.uiDesigner.lw.*;
//import com.intellij.uiDesigner.palette.ComponentItem;
//import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
//import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
//import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
//import com.intellij.uiDesigner.radComponents.RadAbstractGridLayoutManager;
//import com.neuronbit.businessflow.intellij.editor.swing.editor.RadContainer;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SlowOperations;
import com.neuronbit.businessflow.intellij.editor.swing.GuiEditor;
import org.apache.commons.lang3.NotImplementedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.*;

/**
 * The type Form editing util.
 */
public final class FormEditingUtil {
  private FormEditingUtil() {
  }

//  public static boolean canDeleteSelection(final GuiEditor editor) {
//    final ArrayList<RadComponent> selection = getSelectedComponents(editor);
//    if (selection.isEmpty()) return false;
//    final RadRootContainer rootContainer = editor.getRootContainer();
//    if (rootContainer.getComponentCount() > 0 && selection.contains(rootContainer.getComponent(0))) {
//      return false;
//    }
//    return true;
//  }

//  /**
//   * <b>This method must be executed in command</b>
//   *
//   * @param editor the editor in which the selection is deleted.
//   */
//  public static void deleteSelection(final GuiEditor editor) {
//    final List<RadComponent> selection = getSelectedComponents(editor);
//    deleteComponents(selection, true);
//    editor.refreshAndSave(true);
//  }

//  public static void deleteComponents(final Collection<? extends RadComponent> selection, boolean deleteEmptyCells) {
//    if (selection.size() == 0) {
//      return;
//    }
//    final RadRootContainer rootContainer = (RadRootContainer)getRoot(selection.iterator().next());
//    final Set<String> deletedComponentIds = new HashSet<>();
//    for (final RadComponent component : selection) {
//      boolean wasSelected = component.isSelected();
//      final RadContainer parent = component.getParent();
//
//      boolean wasPackedHorz = false;
//      boolean wasPackedVert = false;
//      if (parent.getParent() != null && parent.getParent().isXY()) {
//        final Dimension minSize = parent.getMinimumSize();
//        wasPackedHorz = parent.getWidth() == minSize.width;
//        wasPackedVert = parent.getHeight() == minSize.height;
//      }
//
//      iterate(component, new ComponentVisitor() {
//        @Override
//        public boolean visit(final IComponent c) {
//          RadComponent rc = (RadComponent)c;
//          BindingProperty.checkRemoveUnusedField(rootContainer, rc.getBinding(), null);
//          deletedComponentIds.add(rc.getId());
//          return true;
//        }
//      });
//
//
//      GridConstraints delConstraints = parent.getLayoutManager().isGrid() ? component.getConstraints() : null;
//
//      int index = parent.indexOfComponent(component);
//      parent.removeComponent(component);
//      if (wasSelected) {
//        if (parent.getComponentCount() > index) {
//          parent.getComponent(index).setSelected(true);
//        }
//        else if (index > 0 && parent.getComponentCount() == index) {
//          parent.getComponent(index - 1).setSelected(true);
//        }
//        else {
//          parent.setSelected(true);
//        }
//      }
//      if (delConstraints != null && deleteEmptyCells) {
//        deleteEmptyGridCells(parent, delConstraints);
//      }
//
//      if (wasPackedHorz || wasPackedVert) {
//        final Dimension minSize = parent.getMinimumSize();
//        Dimension newSize = new Dimension(parent.getWidth(), parent.getHeight());
//        if (wasPackedHorz) {
//          newSize.width = minSize.width;
//        }
//        if (wasPackedVert) {
//          newSize.height = minSize.height;
//        }
//        parent.setSize(newSize);
//      }
//    }
//
//    iterate(rootContainer, new ComponentVisitor() {
//      @Override
//      public boolean visit(final IComponent component) {
//        RadComponent rc = (RadComponent)component;
//        for (IProperty p : component.getModifiedProperties()) {
//          if (p instanceof IntroComponentProperty icp) {
//            final String value = icp.getValue(rc);
//            if (deletedComponentIds.contains(value)) {
//              try {
//                icp.resetValue(rc);
//              }
//              catch (Exception e) {
//                // ignore
//              }
//            }
//          }
//        }
//        return true;
//      }
//    });
//  }

//  public static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints) {
//    deleteEmptyGridCells(parent, delConstraints, true);
//    deleteEmptyGridCells(parent, delConstraints, false);
//  }

//  private static void deleteEmptyGridCells(final RadContainer parent, final GridConstraints delConstraints, final boolean isRow) {
//    final RadAbstractGridLayoutManager layoutManager = parent.getGridLayoutManager();
//    for (int cell = delConstraints.getCell(isRow) + delConstraints.getSpan(isRow) - 1; cell >= delConstraints.getCell(isRow); cell--) {
//      if (cell < parent.getGridCellCount(isRow) && GridChangeUtil.canDeleteCell(parent, cell, isRow) == GridChangeUtil.CellStatus.Empty &&
//          !layoutManager.isGapCell(parent, isRow, cell)) {
//        layoutManager.deleteGridCells(parent, cell, isRow);
//      }
//    }
//  }

//  public static final int EMPTY_COMPONENT_SIZE = 5;

//  private static Component getDeepestEmptyComponentAt(JComponent parent, Point location) {
//    int size = parent.getComponentCount();
//
//    for (int i = 0; i < size; i++) {
//      Component child = parent.getComponent(i);
//
//      if (child.isShowing()) {
//        if (child.getWidth() < EMPTY_COMPONENT_SIZE || child.getHeight() < EMPTY_COMPONENT_SIZE) {
//          Point childLocation = child.getLocationOnScreen();
//          Rectangle bounds = new Rectangle();
//
//          bounds.x = childLocation.x;
//          bounds.y = childLocation.y;
//          bounds.width = child.getWidth();
//          bounds.height = child.getHeight();
//          bounds.grow(child.getWidth() < EMPTY_COMPONENT_SIZE ? EMPTY_COMPONENT_SIZE : 0,
//                      child.getHeight() < EMPTY_COMPONENT_SIZE ? EMPTY_COMPONENT_SIZE : 0);
//
//          if (bounds.contains(location)) {
//            return child;
//          }
//        }
//
//        if (child instanceof JComponent) {
//          Component result = getDeepestEmptyComponentAt((JComponent)child, location);
//
//          if (result != null) {
//            return result;
//          }
//        }
//      }
//    }
//
//    return null;
//  }

//  /**
//   * @param x in editor pane coordinates
//   * @param y in editor pane coordinates
//   */
//  public static RadComponent getRadComponentAt(final RadRootContainer rootContainer, final int x, final int y) {
//    Point location = new Point(x, y);
//    SwingUtilities.convertPointToScreen(location, rootContainer.getDelegee());
//    Component c = getDeepestEmptyComponentAt(rootContainer.getDelegee(), location);
//
//    if (c == null) {
//      c = SwingUtilities.getDeepestComponentAt(rootContainer.getDelegee(), x, y);
//    }
//
//    RadComponent result = null;
//
//    while (c != null) {
//      if (c instanceof JComponent) {
//        final RadComponent component = (RadComponent)((JComponent)c).getClientProperty(RadComponent.CLIENT_PROP_RAD_COMPONENT);
//        if (component != null) {
//
//          if (result == null) {
//            result = component;
//          }
//          else {
//            final Point p = SwingUtilities.convertPoint(rootContainer.getDelegee(), x, y, c);
//            if (Painter.getResizeMask(component, p.x, p.y) != 0) {
//              result = component;
//            }
//          }
//        }
//      }
//      c = c.getParent();
//    }
//
//    return result;
//  }

    /**
     * Gets component with binding.
     *
     * @param component the component
     * @param binding   the binding
     * @return the component with binding
     */
//  /**
//   * @return component which has dragger. There is only one component with the dargger
//   *         at a time.
//   */
  @Nullable
//  public static RadComponent getDraggerHost(@NotNull final GuiEditor editor) {
//    final Ref<RadComponent> result = new Ref<>();
//    iterate(
//      editor.getRootContainer(),
//      new ComponentVisitor<RadComponent>() {
//        @Override
//        public boolean visit(final RadComponent component) {
//          if (component.hasDragger()) {
//            result.set(component);
//            return false;
//          }
//          return true;
//        }
//      }
//    );
//
//    return result.get();
//  }


//  public static Cursor getMoveDropCursor() {
//    try {
//      return Cursor.getSystemCustomCursor("MoveDrop.32x32");
//    }
//    catch (Exception ex) {
//      return Cursor.getDefaultCursor();
//    }
//  }

//  public static Cursor getMoveNoDropCursor() {
//    try {
//      return Cursor.getSystemCustomCursor("MoveNoDrop.32x32");
//    }
//    catch (Exception ex) {
//      return Cursor.getDefaultCursor();
//    }
//  }

//  public static Cursor getCopyDropCursor() {
//    try {
//      return Cursor.getSystemCustomCursor("CopyDrop.32x32");
//    }
//    catch (Exception ex) {
//      return Cursor.getDefaultCursor();
//    }
//  }
//
//  /**
//   * @return currently selected components. Method returns the minimal amount of
//   *         selected component which contains all selected components. It means that if the
//   *         selected container contains some selected children then only this container
//   *         will be added to the returned array.
//   */
//  @NotNull
//  public static ArrayList<RadComponent> getSelectedComponents(@NotNull final GuiEditor editor) {
//    final ArrayList<RadComponent> result = new ArrayList<>();
//    calcSelectedComponentsImpl(result, editor.getRootContainer());
//    return result;
//  }

//  private static void calcSelectedComponentsImpl(final ArrayList<? super RadComponent> result, final RadContainer container) {
//    if (container.isSelected()) {
//      if (container.getParent() != null) { // ignore RadRootContainer
//        result.add(container);
//        return;
//      }
//    }
//
//    for (int i = 0; i < container.getComponentCount(); i++) {
//      final RadComponent component = container.getComponent(i);
//      if (component instanceof RadContainer) {
//        calcSelectedComponentsImpl(result, (RadContainer)component);
//      }
//      else {
//        if (component.isSelected()) {
//          result.add(component);
//        }
//      }
//    }
//  }
//
//  /**
//   * @return all selected component inside the {@code editor}
//   */
//  @NotNull
//  public static ArrayList<RadComponent> getAllSelectedComponents(@NotNull final GuiEditor editor) {
//    final ArrayList<RadComponent> result = new ArrayList<>();
//    iterate(
//      editor.getRootContainer(),
//      new ComponentVisitor<RadComponent>() {
//        @Override
//        public boolean visit(final RadComponent component) {
//          if (component.isSelected()) {
//            result.add(component);
//          }
//          return true;
//        }
//      }
//    );
//    return result;
//  }
//
//  public static String getExceptionMessage(Throwable ex) {
//    if (ex instanceof RuntimeException) {
//      final Throwable cause = ex.getCause();
//      if (cause != null && cause != ex) {
//        return getExceptionMessage(cause);
//      }
//    }
//    else if (ex instanceof InvocationTargetException) {
//      final Throwable target = ((InvocationTargetException)ex).getTargetException();
//      if (target != null && target != ex) {
//        return getExceptionMessage(target);
//      }
//    }
//    String message = ex.getMessage();
//    if (ex instanceof ClassNotFoundException) {
//      message =
//        message != null ? UIDesignerBundle.message("error.class.not.found.N", message) : UIDesignerBundle.message("error.class.not.found");
//    }
//    else if (ex instanceof NoClassDefFoundError) {
//      message = message != null
//                ? UIDesignerBundle.message("error.required.class.not.found.N", message)
//                : UIDesignerBundle.message("error.required.class.not.found");
//    }
//    return message;
//  }

  public static IComponent findComponentWithBinding(IComponent component, final String binding) {
    return findComponentWithBinding(component, binding, null);
  }

    /**
     * Find component with binding component.
     *
     * @param component       the component
     * @param binding         the binding
     * @param exceptComponent the except component
     * @return the component
     */
    public static IComponent findComponentWithBinding(IComponent component,
                                                    final String binding,
                                                    @Nullable final IComponent exceptComponent) {
    // Check that binding is unique
    final Ref<IComponent> boundComponent = new Ref<>();
    iterate(
      component,
      new ComponentVisitor() {
        @Override
        public boolean visit(final IComponent component) {
          if (component != exceptComponent && binding.equals(component.getBinding())) {
            boundComponent.set(component);
            return false;
          }
          return true;
        }
      }
    );

    return boundComponent.get();
  }

//  @Nullable
//  public static RadContainer getRadContainerAt(final RadRootContainer rootContainer, final int x, final int y,
//                                               int epsilon) {
//    RadComponent component = getRadComponentAt(rootContainer, x, y);
//    if (isNullOrRoot(component) && epsilon > 0) {
//      // try to find component near specified location
//      component = getRadComponentAt(rootContainer, x - epsilon, y - epsilon);
//      if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x - epsilon, y + epsilon);
//      if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x + epsilon, y - epsilon);
//      if (isNullOrRoot(component)) component = getRadComponentAt(rootContainer, x + epsilon, y + epsilon);
//    }
//
//    if (component != null) {
//      return component instanceof RadContainer
//             ? (RadContainer)component
//             : component.getParent();
//    }
//    return null;
//  }
//
//  private static boolean isNullOrRoot(final RadComponent component) {
//    return component == null || component instanceof RadRootContainer;
//  }

    /**
     * Gets default constraints.
     *
     * @param component the component
     * @return the default constraints
     */
    public static GridConstraints getDefaultConstraints(final RadComponent component) {
    final Palette palette = Palette.getInstance(component.getProject());
    //TODO shunyun 2024/3/13:
//    final ComponentItem item = palette.getItem(component.getComponentClassName());
//    if (item != null) {
//      return item.getDefaultConstraints();
//    }
    return new GridConstraints();
  }

    /**
     * Gets root.
     *
     * @param component the component
     * @return the root
     */
    public static IRootContainer getRoot(IComponent component) {
    while (component != null) {
      if (component.getParentContainer() instanceof IRootContainer) {
        return (IRootContainer)component.getParentContainer();
      }
      component = component.getParentContainer();
    }
    return null;
  }

    /**
     * Iterates component and its children (if any)
     *
     * @param component the component
     * @param visitor   the visitor
     */
    public static void iterate(final IComponent component, final ComponentVisitor visitor) {
    iterateImpl(component, visitor);
  }

  private static boolean iterateImpl(final IComponent component, final ComponentVisitor visitor) {
    final boolean shouldContinue;
    try {
      shouldContinue = visitor.visit(component);
    }
    catch (ProcessCanceledException ex) {
      return false;
    }
    if (!shouldContinue) {
      return false;
    }

    if (!(component instanceof IContainer container)) {
      return true;
    }

    for (int i = 0; i < container.getComponentCount(); i++) {
      final IComponent c = container.getComponent(i);
      if (!iterateImpl(c, visitor)) {
        return false;
      }
    }

    return true;
  }

    /**
     * Collect used bundle names set.
     *
     * @param rootContainer the root container
     * @return the set
     */
    public static Set<String> collectUsedBundleNames(final IRootContainer rootContainer) {
    final Set<String> bundleNames = new HashSet<>();
    iterateStringDescriptors(rootContainer, new StringDescriptorVisitor<>() {
      @Override
      public boolean visit(final IComponent component, final StringDescriptor descriptor) {
        if (descriptor.getBundleName() != null) {
          bundleNames.add(descriptor.getBundleName());
        }
        return true;
      }
    });
    return bundleNames;
  }
//
//  public static Locale[] collectUsedLocales(final Module module, final IRootContainer rootContainer) {
//    final Set<Locale> locales = new HashSet<>();
//    final PropertiesReferenceManager propManager = PropertiesReferenceManager.getInstance(module.getProject());
//    for (String bundleName : collectUsedBundleNames(rootContainer)) {
//      List<PropertiesFile> propFiles = propManager.findPropertiesFiles(module, bundleName.replace('/', '.'));
//      for (PropertiesFile propFile : propFiles) {
//        locales.add(propFile.getLocale());
//      }
//    }
//    return locales.toArray(new Locale[0]);
//  }
//
//  public static void deleteRowOrColumn(final GuiEditor editor, final RadContainer container,
//                                       final int[] cellsToDelete, final boolean isRow) {
//    Arrays.sort(cellsToDelete);
//    final int[] cells = ArrayUtil.reverseArray(cellsToDelete);
//    if (!editor.ensureEditable()) {
//      return;
//    }
//
//    Runnable runnable = () -> {
//      if (!GridChangeUtil.canDeleteCells(container, cells, isRow)) {
//        Set<RadComponent> componentsInColumn = new HashSet<>();
//        for (RadComponent component : container.getComponents()) {
//          GridConstraints c = component.getConstraints();
//          for (int cell : cells) {
//            if (c.contains(isRow, cell)) {
//              componentsInColumn.add(component);
//              break;
//            }
//          }
//        }
//
//        if (componentsInColumn.size() > 0) {
//          String message = isRow
//                           ? UIDesignerBundle.message("delete.row.nonempty", componentsInColumn.size(), cells.length)
//                           : UIDesignerBundle.message("delete.column.nonempty", componentsInColumn.size(), cells.length);
//
//          final int rc = Messages.showYesNoDialog(editor, message,
//                                                  isRow ? UIDesignerBundle.message("delete.row.title")
//                                                        : UIDesignerBundle.message("delete.column.title"), Messages.getQuestionIcon());
//          if (rc != Messages.YES) {
//            return;
//          }
//
//          deleteComponents(componentsInColumn, false);
//        }
//      }
//
//      for (int cell : cells) {
//        container.getGridLayoutManager().deleteGridCells(container, cell, isRow);
//      }
//      editor.refreshAndSave(true);
//    };
//    CommandProcessor.getInstance().executeCommand(editor.getProject(), runnable,
//                                                  isRow ? UIDesignerBundle.message("command.delete.row")
//                                                        : UIDesignerBundle.message("command.delete.column"), null);
//  }
//
//  /**
//   * @return id
//   */
//  public static String generateId(final RadRootContainer rootContainer) {
//    while (true) {
//      final String id = Integer.toString((int)(Math.random() * 1024 * 1024), 16);
//      if (findComponent(rootContainer, id) == null) {
//        return id;
//      }
//    }
//  }
//
//  /**
//   * @return {@link GuiEditor} from the context. Can be {@code null}.
//   */
//  @Nullable
//  public static GuiEditor getEditorFromContext(@NotNull final DataContext context) {
//    final FileEditor editor = PlatformCoreDataKeys.FILE_EDITOR.getData(context);
//    if (editor instanceof UIFormEditor) {
//      return ((UIFormEditor)editor).getEditor();
//    }
//    else {
//      return GuiEditor.DATA_KEY.getData(context);
//    }
//  }
//
//  public static @Nullable GuiEditor getActiveEditor(@NotNull DataContext context) {
//    FileEditor fileEditor = PlatformDataKeys.LAST_ACTIVE_FILE_EDITOR.getData(context);
//    return fileEditor instanceof UIFormEditor ? ((UIFormEditor)fileEditor).getEditor() : null;
//  }
//
//  /**
//   * @param component                topmost container where to find duplicate binding. In most cases
//   *                                 it should be {@link GuiEditor#getRootContainer()}
//   */
//  public static boolean isBindingUnique(
//    final IComponent componentToAssignBinding,
//    final String binding,
//    final IComponent component
//  ) {
//    return findComponentWithBinding(component, binding, componentToAssignBinding) == null;
//  }
//
//  @Nullable
//  public static String buildResourceName(final PsiFile file) {
//    PsiDirectory directory = file.getContainingDirectory();
//    if (directory != null) {
//      PsiPackage pkg = JavaDirectoryService.getInstance().getPackage(directory);
//      String packageName = pkg != null ? pkg.getQualifiedName() : "";
//      if (packageName.length() == 0) {
//        return file.getName();
//      }
//      return packageName.replace('.', '/') + '/' + file.getName();
//    }
//    return null;
//  }

//  @Nullable
//  public static RadContainer getSelectionParent(final List<? extends RadComponent> selection) {
//    RadContainer parent = null;
//    for (RadComponent c : selection) {
//      if (parent == null) {
//        parent = c.getParent();
//      }
//      else if (parent != c.getParent()) {
//        parent = null;
//        break;
//      }
//    }
//    return parent;
//  }

//  public static Rectangle getSelectionBounds(List<? extends RadComponent> selection) {
//    int minRow = Integer.MAX_VALUE;
//    int minCol = Integer.MAX_VALUE;
//    int maxRow = 0;
//    int maxCol = 0;
//
//    for (RadComponent c : selection) {
//      minRow = Math.min(minRow, c.getConstraints().getRow());
//      minCol = Math.min(minCol, c.getConstraints().getColumn());
//      maxRow = Math.max(maxRow, c.getConstraints().getRow() + c.getConstraints().getRowSpan());
//      maxCol = Math.max(maxCol, c.getConstraints().getColumn() + c.getConstraints().getColSpan());
//    }
//    return new Rectangle(minCol, minRow, maxCol - minCol, maxRow - minRow);
//  }

//  public static boolean isComponentSwitchedInView(@NotNull RadComponent component) {
//    while (component.getParent() != null) {
//      if (!component.getParent().getLayoutManager().isSwitchedToChild(component.getParent(), component)) {
//        return false;
//      }
//      component = component.getParent();
//    }
//    return true;
//  }

    /**
     * Selects the component and ensures that the tabbed panes containing the component are
     * switched to the correct tab.
     *
     * @param editor    the editor
     * @param component the component to select. @return true if the component is enclosed in at least one tabbed pane, false otherwise.
     * @return the boolean
     */
    public static boolean selectComponent(final GuiEditor editor, @NotNull final RadComponent component) {
//    boolean hasTab = false;
    throw new NotImplementedException();
//    RadComponent parent = component;
//    while (parent.getParent() != null) {
//      if (parent.getParent().getLayoutManager().switchContainerToChild(parent.getParent(), parent)) {
//        hasTab = true;
//      }
//      parent = parent.getParent();
//    }
//    component.setSelected(true);
//    editor.setSelectionLead(component);
//    return hasTab;
  }
//
//  public static void selectSingleComponent(final GuiEditor editor, final RadComponent component) {
//    final RadContainer root = (RadContainer)getRoot(component);
//    if (root == null) return;
//
//    ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
//    // this can return null if the click to select the control also requested to grab the focus -
//    // the component tree will be instantiated after the event has been processed completely
//    if (builder != null) {
//      builder.beginUpdateSelection();
//    }
//    try {
//      clearSelection(root);
//      selectComponent(editor, component);
//      editor.setSelectionAnchor(component);
//      editor.scrollComponentInView(component);
//    }
//    finally {
//      if (builder != null) {
//        builder.endUpdateSelection();
//      }
//    }
//  }
//
//  public static void selectComponents(final GuiEditor editor, List<? extends RadComponent> components) {
//    if (components.size() > 0) {
//      RadComponent component = components.get(0);
//      ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
//      if (builder == null) {
//        // race condition when handling event?
//        return;
//      }
//      builder.beginUpdateSelection();
//      try {
//        clearSelection((RadContainer)getRoot(component));
//        for (RadComponent aComponent : components) {
//          selectComponent(editor, aComponent);
//        }
//      }
//      finally {
//        builder.endUpdateSelection();
//      }
//    }
//  }
//
//  public static boolean isDropOnChild(final DraggedComponentList draggedComponentList,
//                                      final ComponentDropLocation location) {
//    if (location.getContainer() == null) {
//      return false;
//    }
//
//    for (RadComponent component : draggedComponentList.getComponents()) {
//      if (isChild(location.getContainer(), component)) {
//        return true;
//      }
//    }
//    return false;
//  }
//
//  private static boolean isChild(RadContainer maybeChild, RadComponent maybeParent) {
//    while (maybeChild != null) {
//      if (maybeParent == maybeChild) {
//        return true;
//      }
//      maybeChild = maybeChild.getParent();
//    }
//    return false;
//  }

    /**
     * Find create components method psi method.
     *
     * @param aClass the a class
     * @return the psi method
     */
    public static PsiMethod findCreateComponentsMethod(final PsiClass aClass) {
    PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();
    PsiMethod method;
    try {
      method = factory.createMethodFromText("void " + AsmCodeGenerator.CREATE_COMPONENTS_METHOD_NAME + "() {}",
                                            aClass);
    }
    catch (IncorrectOperationException e) {
      throw new RuntimeException(e);
    }
    return aClass.findMethodBySignature(method, true);
  }
//
//  public static Object getNextSaveUndoGroupId(final Project project) {
//    final GuiEditor guiEditor = DesignerToolWindowManager.getInstance(project).getActiveFormEditor();
//    return guiEditor == null ? null : guiEditor.getNextSaveGroupId();
//  }

//  public static int adjustForGap(final RadContainer container, final int cellIndex, final boolean isRow, final int delta) {
//    if (container.getGridLayoutManager().isGapCell(container, isRow, cellIndex)) {
//      return cellIndex + delta;
//    }
//    return cellIndex;
//  }
//
//  public static int prevRow(final RadContainer container, final int row) {
//    return adjustForGap(container, row - 1, true, -1);
//  }
//
//  public static int nextRow(final RadContainer container, final int row) {
//    return adjustForGap(container, row + 1, true, 1);
//  }
//
//  public static int prevCol(final RadContainer container, final int col) {
//    return adjustForGap(container, col - 1, false, -1);
//  }
//
//  public static int nextCol(final RadContainer container, final int col) {
//    return adjustForGap(container, col + 1, false, 1);
//  }
//
//  @Nullable
//  public static IButtonGroup findGroupForComponent(final IRootContainer radRootContainer, @NotNull final IComponent component) {
//    for (IButtonGroup group : radRootContainer.getButtonGroups()) {
//      if (ArrayUtil.contains(component.getId(), group.getComponentIds())) {
//          return group;
//      }
//    }
//    return null;
//  }

//  public static List<RadComponent> remapToActionTargets(final List<? extends RadComponent> selection) {
//    ArrayList<RadComponent> result = new ArrayList<>(selection.size());
//    for (int i = 0; i < selection.size(); i++) {
//      final RadComponent c = selection.get(i);
//      if (c.getParent() != null) {
//        result.add(c.getParent().getActionTargetComponent(c));
//      }
//    }
//    return result;
//  }
//
//  public static void showPopupUnderComponent(final JBPopup popup, final RadComponent selectedComponent) {
//    // popup.showUnderneathOf() doesn't work on invisible components
//    Rectangle rc = selectedComponent.getBounds();
//    Point pnt = new Point(rc.x, rc.y + rc.height);
//    popup.show(new RelativePoint(selectedComponent.getDelegee().getParent(), pnt));
//  }

    /**
     * The interface String descriptor visitor.
     *
     * @param <T> the type parameter
     */
    public interface StringDescriptorVisitor<T extends IComponent> {
        /**
         * Visit boolean.
         *
         * @param component  the component
         * @param descriptor the descriptor
         * @return the boolean
         */
        boolean visit(T component, StringDescriptor descriptor);
  }


    /**
     * Iterate string descriptors.
     *
     * @param component the component
     * @param visitor   the visitor
     */
    public static void iterateStringDescriptors(final IComponent component,
                                              final StringDescriptorVisitor<? super IComponent> visitor) {
    iterate(component, new ComponentVisitor<>() {

      @Override
      public boolean visit(final IComponent component) {
        throw new NotImplementedException();
//        for (IProperty prop : component.getModifiedProperties()) {
//          Object value = prop.getPropertyValue(component);
//          if (value instanceof StringDescriptor) {
//            if (!visitor.visit(component, (StringDescriptor)value)) {
//              return false;
//            }
//          }
//        }
//        if (component.getParentContainer() instanceof ITabbedPane) {
//          StringDescriptor tabTitle =
//            ((ITabbedPane)component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TITLE_PROPERTY);
//          if (tabTitle != null && !visitor.visit(component, tabTitle)) {
//            return false;
//          }
//          StringDescriptor tabToolTip =
//            ((ITabbedPane)component.getParentContainer()).getTabProperty(component, ITabbedPane.TAB_TOOLTIP_PROPERTY);
//          if (tabToolTip != null && !visitor.visit(component, tabToolTip)) {
//            return false;
//          }
//        }
//        if (component instanceof IContainer) {
//          final StringDescriptor borderTitle = ((IContainer)component).getBorderTitle();
//          if (borderTitle != null && !visitor.visit(component, borderTitle)) {
//            return false;
//          }
//        }
//        return true;
      }
    });
  }

//  public static void clearSelection(@NotNull final RadContainer container) {
//    container.setSelected(false);
//
//    for (int i = 0; i < container.getComponentCount(); i++) {
//      final RadComponent c = container.getComponent(i);
//      if (c instanceof RadContainer) {
//        clearSelection((RadContainer)c);
//      }
//      else {
//        c.setSelected(false);
//      }
//    }
//  }

    /**
     * Finds component with the specified {@code id} starting from the
     * {@code container}. The method goes recursively through the hierarchy
     * of components. Note, that if {@code container} itself has {@code id}
     * then the method immediately retuns it.
     *
     * @param component the component
     * @param id        the id
     * @return the found component.
     */
    @Nullable
  public static IComponent findComponent(@NotNull final IComponent component, @NotNull final String id) {
    if (id.equals(component.getId())) {
      return component;
    }
    if (!(component instanceof IContainer uiContainer)) {
      return null;
    }

    for (int i = 0; i < uiContainer.getComponentCount(); i++) {
      final IComponent found = findComponent(uiContainer.getComponent(i), id);
      if (found != null) {
        return found;
      }
    }
    return null;
  }

    /**
     * Find class to bind psi class.
     *
     * @param module          the module
     * @param classToBindName the class to bind name
     * @return the psi class
     */
    @Nullable
  public static PsiClass findClassToBind(@NotNull final Module module, @NotNull final String classToBindName) {
    //TODO shunyun 2024/4/3: 这里为什么没有用 stubIndex呢？
    try (AccessToken ignore = SlowOperations.knownIssue("IDEA-307701, EA-266779")) {
      return JavaPsiFacade.getInstance(module.getProject())
        .findClass(classToBindName.replace('$', '.'), module.getModuleWithDependenciesAndLibrariesScope(false));
    }
  }

    /**
     * The interface Component visitor.
     *
     * @param <Type> the type parameter
     */
    public interface ComponentVisitor<Type extends IComponent> {
        /**
         * Visit boolean.
         *
         * @param component the component
         * @return true if iteration should continue
         */
        boolean visit(Type component);
  }
}
